/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 项目名：	rumba
 * 文件名：	BTypeInfoMgr.java
 * 模块说明：	
 * 修改历史：
 * Dec 10, 2007 - lxm - 创建。
 */
package com.hd123.rumba.gwt.cpnts.filter.server.biz;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;

import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.gwt.cpnts.filter.client.biz.BasicTypeInfo;
import com.hd123.rumba.gwt.cpnts.filter.client.biz.ClassTypeInfo;
import com.hd123.rumba.gwt.cpnts.filter.client.biz.DataTypeEnum;
import com.hd123.rumba.gwt.cpnts.filter.client.biz.FieldInfo;
import com.hd123.rumba.gwt.cpnts.filter.client.biz.TypeInfo;
import com.hd123.rumba.runtime.IManager;
import com.hd123.rumba.runtime.PerzEntity;
import com.hd123.rumba.runtime.PerzServant;
import com.hd123.rumba.runtime.biz.BManager;
import com.hd123.rumba.util.ObjectUtil;

/**
 * 类型信息 | 业务层 | 管理员 | 实现类
 * <p>
 * 
 * 内部包含一个缓冲，以提高取得类型信息的运行效率。
 * 
 * @author lxm
 * 
 */
public class BTypeInfoMgr extends BManager implements IBTypeInfoMgr {

  @Override
  public IManager getPerzMgr() throws BusinessException {
    return null;
  }

  /** 缓冲 */
  private HashMap<String, ClassTypeInfo> buffer = new HashMap();

  public ClassTypeInfo getClassTypeInfo(String className) throws BusinessException {
    ObjectUtil.checkParameterNotNull(className, "className");

    ClassTypeInfo typeInfo = buffer.get(className);
    if (typeInfo == null) {
      Class clazz = getClassByName(className);
      typeInfo = new ClassTypeInfo();
      decodeClass(typeInfo, clazz);
      buffer.put(className, typeInfo);
    }
    return typeInfo.clone();
  }

  private Class getClassByName(String className) throws BusinessException {
    try {
      return Class.forName(className);
    } catch (ClassNotFoundException e) {
      throw new BusinessException(e);
    }
  }

  /** 解析类 */
  private void decodeClass(ClassTypeInfo classTypeInfo, Class clazz) throws BusinessException {
    assert classTypeInfo != null;
    assert clazz != null;
    assert classTypeInfo.getFields() != null;

    if (this.isServant(clazz))
      classTypeInfo.setIsServant(Boolean.TRUE);
    Class constantClass = getConstantClass(clazz);
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
      int modifiers = field.getModifiers();
      if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers))
        continue;
      FieldInfo fieldInfo = decodeField(field, constantClass);
      fieldInfo.setOwner(classTypeInfo);
      classTypeInfo.getFields().add(fieldInfo);
    }
  }

  /** 判断是否是服务类。 */
  private boolean isServant(Class clazz) throws BusinessException {
    return clazz.isAnnotationPresent(PerzServant.class);
  }

  /** 取得对应的常量类。若找不到则返回null。 */
  private Class getConstantClass(Class clazz) throws BusinessException {
    assert clazz != null;
    if (clazz.isAnnotationPresent(PerzEntity.class)) {
      PerzEntity annoEntity = (PerzEntity) clazz.getAnnotation(PerzEntity.class);
      return annoEntity.constant();
    }
    if (clazz.isAnnotationPresent(PerzServant.class)) {
      PerzServant annoEntity = (PerzServant) clazz.getAnnotation(PerzServant.class);
      return annoEntity.constant();
    } else {

      // 旧标准：查找指定类相同包下的以"C"为前缀的类。
      String entityName = clazz.getName();
      assert entityName != null;
      String[] words = entityName.split("\\.");
      assert words.length > 0;
      String shortName = words[words.length - 1];
      if (shortName.getBytes()[0] == 'I')
        words[words.length - 1] = "C" + shortName.substring(1);
      else
        words[words.length - 1] = "C" + shortName;
      StringBuffer sb = new StringBuffer();
      for (String word : words) {
        if (sb.length() > 0)
          sb.append(".");
        sb.append(word);
      }
      try {
        return Class.forName(sb.toString());
      } catch (ClassNotFoundException e) {
        throw new BusinessException(e);
      }
    }
  }

  /** 解析指定的字段，取得类型信息。 */
  private FieldInfo decodeField(Field field, Class constantClass) throws BusinessException {
    assert field != null;
    assert constantClass != null;

    FieldInfo fieldInfo = new FieldInfo();
    fieldInfo.setName(field.getName());

    // 取得字段的类型信息。
    Class fieldClass = field.getType();
    Class[] fieldClasses = fieldClass.getClasses();
    HashSet<Class> fieldClassSet = new HashSet<Class>();
    for (Class fclass : fieldClasses) {
      fieldClassSet.add(fclass);
    }
    DataTypeEnum dataType = DataTypeEnum.Unknown;
    if (fieldClassSet.contains(Long.class) || fieldClassSet.contains(Integer.class))
      dataType = DataTypeEnum.Integer;
    else if (fieldClassSet.contains(Float.class) || fieldClassSet.contains(Double.class)
        || fieldClassSet.contains(BigDecimal.class))
      dataType = DataTypeEnum.Decimal;
    else if (fieldClassSet.contains(Boolean.class))
      dataType = DataTypeEnum.Boolean;
    else if (fieldClassSet.contains(Date.class))
      dataType = DataTypeEnum.Date;
    else if (fieldClassSet.contains(String.class))
      dataType = DataTypeEnum.String;
    else if (fieldClassSet.contains(Collection.class))
      dataType = DataTypeEnum.Bag;
    else
      dataType = DataTypeEnum.Class;
    TypeInfo typeInfo;
    if (dataType.isBasic())
      typeInfo = new BasicTypeInfo();
    else
      typeInfo = new ClassTypeInfo();
    typeInfo.setDataType(dataType);

    typeInfo.setCaption(fetchFieldCaption(field, constantClass));
    fieldInfo.setTypeInfo(typeInfo);

    return fieldInfo;
  }

  private String fetchFieldCaption(Field field, Class constantClass) throws BusinessException {
    String caption = field.getName();
    try {
      Field cf = constantClass.getField("CAPTION_" + field.getName().toUpperCase());
      int mod = cf.getModifiers();
      if (Modifier.isStatic(mod) && Modifier.isPublic(mod))
        caption = (String) cf.get(null);
    } catch (Exception e) {
      // Do Nothing
    }
    return caption;
  }

}
